#include <ximera/system/application.hpp>
#include <ximera/logger.hpp>
#include <ximera/xml/xmldocument.hpp>
#include <ximera/xml/xmliterator.hpp>
#include <ximera/xml/xmlelement.hpp>

#include <iostream>

struct AppTestHandler : ximera::system::AppHandler
{
	virtual void onStart(ximera::system::AppEventArgs& args)
    {
        try
        {
            _app = &args.app;
            testScripting(args.app);
            //testAudio(app);
            testXml(args.app);
            testInput(args.app);
        }
        catch (ximera::Exception& e)
        {
            args.app.shouldClose(true);
            XIMERA_LOG() << e << std::endl;
        }
    }

	virtual void onUpdate(ximera::system::UpdateEventArgs&)
    {
        static int x = 10;
        //std::cout << "Updating with " << secs << " seconds\n";

        //listener->position(listener->position() + ximera::math::Vector3::E1 * secs);
    }

private:
    ximera::system::Application* _app;

    ximera::SharedPtr<ximera::graphics::IWorld> graphicsWorld;
    ximera::SharedPtr<ximera::graphics::ICamera> camera;
    ximera::SharedPtr<ximera::graphics::IViewport> viewport;

    void testGraphics(ximera::system::Application& app)
    {
        using namespace ximera;
        graphicsWorld.reset(app.graphicsSystem()->createWorld());
        camera.reset(graphicsWorld->createCamera(L"default"));
        viewport.reset(graphicsWorld->createViewport(camera.get()));

        graphics::ISceneNode* cameraNode = graphicsWorld->rootNode()->createChild(L"camera");
        cameraNode->attach(camera.get());
    }

    void testScripting(ximera::system::Application& app)
    {
        using namespace ximera;
        SharedPtr<scripting::IVirtualMachine> vm(app.scriptingSystem()->createVirtualMachine());
        SharedPtr<scripting::IScript> script(app.scriptingSystem()->createScript());

        script->data(L"vec1 = ximera.math.Vector3(10, 3, 2); \n"
            L"vec2 = ximera.math.Vector3(1, 2, 0); \n"
            L"print(vec1 * vec2);");

        vm->run(script);

        vm->run(L"print('hello'); vec3 = ximera.math.Vector3(10, 3, 2); \n"
            L"vec4 = ximera.math.Vector3(1, 2, 0); \n"
            L"print('hola'); \n"
            L"vec5 = vec3 + vec4; \n"
            L"print('hola'); \n"
            L"vec4.y = 0; \n"
            L"print(vec5 * vec4); \n");
        //L"print(vec3:at(1));");
        //L"print(vec5:length());");
    }

    ximera::SharedPtr<ximera::audio::IWorld> audioWorld;
    ximera::SharedPtr<ximera::audio::IListener> listener;
    ximera::SharedPtr<ximera::audio::ISound> sound;    

    void testAudio(ximera::system::Application& app)
    {
        using namespace ximera;
        audioWorld.reset(app.audioSystem()->createWorld());
        listener.reset(audioWorld->createListener());
        sound.reset(audioWorld->loadSound(L"explosion.wav"));

        sound->loopMode(audio::LoopMode::On);
        sound->play();
    }

    void testXml(ximera::system::Application& app)
    {
        using namespace ximera;
        xml::XmlDocument doc;
        doc.loadXml(L"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
            L"<rootnode>"
            L"  <child1 attr1=\"culo\" />"
            L"  <child2>ano</child2>"
            L"  <child2>ano343</child2>"
            L"  <child1 attr1=\"culo\" />"
            L"  <child1 />"
            L"  <child2>ano5<b>asa</b>cuca</child2>"
            L"  <child2>ano123</child2>"
            L"</rootnode>");
        //doc.loadXml(L"<?xml version=\"1.0\" encoding=\"utf-8\"?>");

        for (xml::XmlNode::ChildIterator it = doc.firstChild()->childBegin(); it != doc.firstChild()->childEnd(); ++it)
        {
            XIMERA_LOG() << "node: " << (*it)->value() << " type: " << static_cast<int>((*it)->type()) << std::endl;
        }

        XIMERA_LOG() << "-----\n";

        for (xml::XmlIterator<xml::XmlElement> it(doc.rootElement(), L"child2"); it; ++it)
        {
            XIMERA_LOG() << "node: " << it->value() << " type: " << static_cast<int>(it->type()) << std::endl;
            XIMERA_LOG() << "   text: " << it->retrieveText() << std::endl;
        }
    }

    void testInput(ximera::system::Application& app)
    {
        app.inputSystem()->keyboard()->onKeyUp() += 
            boost::bind(&AppTestHandler::keyboard_KeyUp, this, _1, _2);
    }

    void keyboard_KeyUp(ximera::input::IKeyboard* sender, ximera::input::KeyCode const& keyCode)
    {
        if (keyCode == ximera::input::KeyCode::Escape)
            _app->shouldClose(true);
    }
};

int main()
{
    using namespace ximera;

    try
    {
        XIMERA_LOG().stream(&std::wcout);

        system::AppSettings settings;
        settings[L"ximera.plugins.input"] = XIMERA_PLUGIN(L"XimeraDInput8");
        settings[L"ximera.plugins.scripting"] = XIMERA_PLUGIN(L"XimeraLua");
        //settings[L"ximera.plugins.audio"] = XIMERA_PLUGIN(L"XimeraOpenAL");
        settings[L"ximera.plugins.graphics"] = XIMERA_PLUGIN(L"XimeraOgre");
        settings[L"ximera.ogre.showdialog"] = L"1";

        system::Application app(settings);

        AppTestHandler handler;
        app.addHandler(handler);

        return app.run();
    }
    catch (ximera::Exception& e)
    {
        XIMERA_LOG() << e << std::endl;
    }
}
